<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Logging with twisted.python.log</title>
  </head>

  <body>
    <h1>Logging with twisted.python.log</h1>

    <h2>Basic usage</h2>

    <p>Twisted provides a simple and flexible logging system in the <code
    class="API">twisted.python.log</code> module.  It has three commonly used
    functions:</p>

    <dl>
      <dt><code class="API" base="twisted.python.log.LogPublisher">msg</code></dt>
      <dd>Logs a new message.  For example:
        <pre class="python">
from twisted.python import log
log.msg('Hello, world.')
        </pre>
      </dd>

      <dt><code class="API" base="twisted.python.log">err</code></dt>
      <dd>Writes a failure to the log, including traceback information (if any).
      You can pass it a <code class="API"
      base="twisted.python.failure">Failure</code> or Exception instance, or
      nothing.  If you pass something else, it will be converted to a string
      with <code>repr</code> and logged.

      If you pass nothing, it will construct a Failure from the
      currently active exception, which makes it convenient to use in an <code
      class="python">except</code> clause:
        <pre class="python">
try:
    x = 1 / 0
except:
    log.err()   # will log the ZeroDivisionError
        </pre>
      </dd>

      <dt><code class="API" base="twisted.python.log">startLogging</code></dt>
      <dd>Starts logging to a given file-like object.  For example:
        <pre class="python">
log.startLogging(open('/var/log/foo.log', 'w'))
        </pre>
      or:
        <pre class="python">
log.startLogging(sys.stdout)
        </pre>
      or:
        <pre class="python">
from twisted.python.logfile import DailyLogFile

log.startLogging(DailyLogFile.fromFullPath("/var/log/foo.log"))
        </pre>

      By default, <code>startLogging</code> will also redirect anything written
      to <code>sys.stdout</code> and <code>sys.stderr</code> to the log.  You
      can disable this by passing <code class="python">setStdout=False</code> to
      <code>startLogging</code>.
      </dd>
    </dl>

    <p>Before <code>startLogging</code> is called, log messages will be
    discarded and errors will be written to stderr.</p>

    <h3>Logging and twistd</h3>

    <p>If you are using <code class="shell">twistd</code> to run your daemon, it
    will take care of calling <code>startLogging</code> for you, and will also
    rotate log files.  See <a href="application.xhtml#twistd">twistd and tac</a>
    and the <code class="shell">twistd</code> man page for details of using
    twistd.</p>

    <h3>Log files</h3>

    <p>The <code class="API">twisted.python.logfile</code> module provides
    some standard classes suitable for use with <code>startLogging</code>, such
    as <code class="API" base="twisted.python.logfile">DailyLogFile</code>,
    which will rotate the log to a new file once per day.</p>

    <h3>Using the standard library logging module</h3>

    <p>If your application uses the
    Python <a href="http://docs.python.org/library/logging.html">standard
    library logging module</a> or you want to use its easy configuration but
    don't want to lose twisted-produced messages, the observer
    <code class="API" base="twisted.python.log">PythonLoggingObserver</code>
    should be useful to you.
    </p>

    <p>You just start it like any other observer:
        <pre class="python">
observer = log.PythonLoggingObserver()
observer.start()
        </pre>

    Then <a href="http://docs.python.org/library/logging.html">configure the
    standard library logging module</a> to behave as you want.
    </p>

    <p>This method allows you to customize the log level received by the
    standard library logging module using the <code>logLevel</code> keyword:
        <pre class="python">
log.msg("This is important!", logLevel=logging.CRITICAL)
log.msg("Don't mind", logLevel=logging.DEBUG)
        </pre>
    Unless <code>logLevel</code> is provided, logging.INFO is used for <code>log.msg</code>
    and <code>logging.ERROR</code> is used for <code>log.err</code>.
    </p>

    <p>One special care should be made when you use special configuration of
    the standard library logging module: some handlers (e.g. SMTP, HTTP) use the network and
    so can block inside the reactor loop. <em>Nothing</em> in <code>PythonLoggingObserver</code> is
    done to prevent that.</p>

    <h2>Writing log observers</h2>

    <p>Log observers are the basis of the Twisted logging system.
    Whenever <code>log.msg</code> (or <code>log.err</code>) is called, an
    event is emitted.  The event is passed to each observer which has been
    registered.  There can be any number of observers, and each can treat
    the event in any way desired.
    An example of
    a log observer in Twisted is the <code>emit</code> method of <code class="API"
    base="twisted.python.log">FileLogObserver</code>.
    <code>FileLogObserver</code>, used by
    <code>startLogging</code>, writes events to a log file.  A log observer
    is just a callable that accepts a dictionary as its only argument.  You can
    then register it to receive all log events (in addition to any other
    observers):</p>

    <pre class="python">
twisted.python.log.addObserver(yourCallable)
    </pre>

    <p>The dictionary will have at least two items:</p>

    <dl>
      <dt>message</dt>
      <dd>The message (a list, usually of strings)
      for this log event, as passed to <code>log.msg</code> or the
      message in the failure passed to <code>log.err</code>.</dd>

      <dt>isError</dt>
      <dd>This is a boolean that will be true if this event came from a call to
      <code>log.err</code>.  If this is set, there may be a <code>failure</code>
      item in the dictionary as will, with a Failure object in it.</dd>
    </dl>

    <p>Other items the built in logging functionality may add include:</p>

    <dl>
      <dt>printed</dt>
      <dd>This message was captured from <code>sys.stdout</code>, i.e. this
      message came from a <code>print</code> statement.  If
      <code>isError</code> is also true, it came from
      <code>sys.stderr</code>.</dd>
    </dl>

    <p>You can pass additional items to the event dictionary by passing keyword
    arguments to <code>log.msg</code> and <code>log.err</code>.  The standard
    log observers will ignore dictionary items they don't use.</p>

    <p>Important notes:</p>

    <ul>
      <li>Never block in a log observer, as it may run in main Twisted thread.
      This means you can't use socket or syslog standard library logging backends.</li>

      <li>The observer needs to be thread safe if you anticipate using threads
      in your program.</li>
    </ul>

    <h2>Customizing <code>twistd</code> logging</h2>
    <p>
    The behavior of the logging that <code>twistd</code> does can be
    customized either with the <code>--logger</code> option or by setting the
    <code>ILogObserver</code> component on the application object.  See the <a
    href="application.xhtml">Application document</a> for more information.
    </p>

  </body>
</html>

